package worldobjects;

import java.awt.Color;

import raytracing.Ray;
import raytracing.RaycastResult;
import structs.StandardValues;
import structs.Vector3;

public class Triangle implements IWorldObject{

	public Vector3 v1;
	public Vector3 v2;
	public Vector3 v3;
	public Vector3 n1;
	public Vector3 n2;
	public Vector3 n3;
	public Color diffuseColor;
	public Color specularColor;
	public float specularIntensity;
	public boolean castsShadow = true;
	
	public Triangle(Vector3 a, Vector3 b, Vector3 c)
	{
		v1 = a;
		v2 = b;
		v3 = c;
		diffuseColor = StandardValues.DIFFUSE_COLOR;
		specularColor = StandardValues.SPECULAR_COLOR;
		specularIntensity = StandardValues.SPECULAR_INTENSITY;
	}

	@Override
	public boolean isHit(Ray ray, float minDist, float maxDist, RaycastResult result) {
		result.distance = Integer.MAX_VALUE;
				
		float a = v1.X - v2.X;
		float b = v1.Y - v2.Y;
		float c = v1.Z - v2.Z;
		float d = v1.X - v3.X;
		float e = v1.Y - v3.Y;
		float f = v1.Z - v3.Z;
		float g = ray.Direction.X;
		float h = ray.Direction.Y;
		float i = ray.Direction.Z;
		float j = v1.X - ray.Origin.X;
		float k = v1.Y - ray.Origin.Y;
		float l = v1.Z - ray.Origin.Z;

		float beta = Integer.MAX_VALUE;
		float gamma = Integer.MAX_VALUE;
		float t = Integer.MAX_VALUE;

		float eiMinushf = e * i - h * f;
		float gfMinusdi = g * f - d * i;
		float dhMinuseg = d * h - e * g;
		float akMinusjb = a * k - j * b;
		float jcMinusal = j * c - a * l;
		float blMinuskc = b * l - k * c;
		float M = a * eiMinushf + b * gfMinusdi + c * dhMinuseg;

		t = -(f * akMinusjb + e * jcMinusal + d * blMinuskc) / M;
		if(t<minDist || t>maxDist)
			return false;
		
		gamma = (i * akMinusjb + h * jcMinusal + g * blMinuskc) / M;
		if(gamma<0 || gamma >1)
			return false;
		
		beta = (j * eiMinushf + k * gfMinusdi + l * dhMinuseg) / M;
		if(beta<0 || beta>1-gamma)
			return false;
		
		result.distance = t;
		result.ray = ray;		
		float alpha = 1-beta-gamma;
		result.normal = interpolateNormal(alpha, beta, gamma);
				
		result.diffuseColor = diffuseColor;
		result.specularColor = specularColor;
		result.specularIntensity = specularIntensity;		
		
		return true;
	}
	
	private Vector3 interpolateNormal(float alpha, float beta, float gamma)
	{
		float x = n1.X*alpha + n2.X*beta + n3.X*gamma;
		float y = n1.Y*alpha + n2.Y*beta + n3.Y*gamma;
		float z = n1.Z*alpha + n2.Z*beta + n3.Z*gamma;
		Vector3 ret = new Vector3(x,y,z);
		ret.normalize();
		return ret;
	}

	@Override
	public BoundingBox getBoundingBox() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean castsShadow() {
		return castsShadow;
	}
}
